package model;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
/**
*  La clase Sistema Millenium administra las tarjetas y estaciones, ademas de contener los metodos necesarios para el correcto 
* desarrollo del programa.
* 
* @version r13 15/05/09
* @author Sergio Morlan Reborido
* @author Juan Ramon Nogueira Moreiras
*/
public class SistemaMillennium implements ISistemaPrepago {
	private HashMap<String, Object> _tarjetas=new HashMap();
	private HashMap<String, Object> _estaciones=new HashMap();
	public SistemaMillennium()
	{	
		
	}

/**
* Carga en la tarjeta el saldo que deseamos, recuperando la tarjeta y aumentando el saldo en el campo correspondiente
* @param idTarjeta El identificador de la tarjeta sobre la que se va a realizar la carga.
* @param saldoExtra El saldo que ingresamos en la tarjeta
* @param fecha La fecha en la que la operacion se lleva a cabo.
* @return El entero cero
*/
	public int cargarTarjeta(String idTarjeta, int saldoExtra, Date fecha) throws OperacionInvalidaException 
	{
		saldoExtra=saldoExtra*100;
		if(saldoExtra<500)
			throw new OperacionInvalidaException("la carga es insuficiente");
		else
		{
			Tarjeta t=(Tarjeta)_tarjetas.get(idTarjeta);
			if(t==null)
				throw new OperacionInvalidaException("tarjeta no valida para la carga");
			else
			{
				int saldo=t.mirarSaldo();
				if(saldo+saldoExtra>6000)
					throw new OperacionInvalidaException("no se puede cargar porque excede el saldo maximo");
				else
				{
					t.cargar(saldoExtra);
					Operacion op=new Cargar(fecha,saldoExtra,t);
					t.añadirOp(op);
				}
			}
		}	
	    return 0;
	}

/**
* Consulta el saldo de una tarjeta, recuperandola y buscando el campo correspondiente
* @param idTarjeta El identificador de la tarjeta sobre la que se va a consultar el saldo
* @return x El Saldo disponible
*/
   public int consultarSaldo(String idTarjeta) throws OperacionInvalidaException 
	{
		Tarjeta t=(Tarjeta)_tarjetas.get(idTarjeta);
		int x=t.mirarSaldo();
	    return x;
   }        
        
/**
* Consulta las estaciones existentes en la lista de estaciones
* @return it Iterator de todas las estaciones creadas.
*/
	public Iterator consultarEstaciones() 
	{
	    Iterator it = _estaciones.entrySet().iterator();
	    return it;
	}

/**
* Consulta las tarjetas existentes en la lista de tarjetas
* @return it Iterator de todas las tarjetas creadas.
*/
	public Iterator consultarTarjetas() 
	{
		Iterator it = _tarjetas.entrySet().iterator();
	    return it;
	}

/**
* Crea una estacion nueva a partir de los datos que recibe, llamando al constructor de la clase estacion
* @param id El identificador de la estacion nueva
* @param zona El lugar donde se va a crear la nueva estacion
* @param nombre El nombre que va a recibir la nueva estacion
*/
	public void crearEstacion(String id, String zona, String nombre) throws OperacionInvalidaException 
	{			
		if ((Estacion)_estaciones.get(id)==null)
		{
			Estacion est=new Estacion(id,zona,nombre);
			_estaciones.put(id,est);
		}
		else
			throw new OperacionInvalidaException("Estacion no se puede crear porque ya existe ese identificador");
	    return;
	}

/**
* Crea una nueva tarjeta a partir de los datos que recibe, llamando al constructor de la subclase especifica segun el tipo de tarjeta
* @param id El identificador de la tarjeta nueva
* @param nombre El nombre del usuario de la tarjeta
* @param tipoTarjeta El tipo de la tarjeta que vamos a crear 
*/	
   public void crearTarjeta(String id, int saldoInicial, String nombre, String tipoTarjeta) throws OperacionInvalidaException 
	{	
		if ((Tarjeta)_tarjetas.get(id)==null)
		{
			if(saldoInicial>60)
				throw new OperacionInvalidaException("No se puede crear la tarjeta porque el saldo es excesivo");
			else
			{
				saldoInicial=saldoInicial*100;
				if (tipoTarjeta.equals("social"))
				{
					Social tar=new Social(id,saldoInicial,nombre,"SOCIAL");_tarjetas.put(id,tar);
				}
				else if (tipoTarjeta.equals("general"))
				{
					General tar=new General(id,saldoInicial,nombre,"GENERAL");_tarjetas.put(id,tar);
				}
				else if (tipoTarjeta.equals("universitaria"))
				{
					Universitaria tar=new Universitaria(id,saldoInicial,nombre,"UNIVERSITARIA");_tarjetas.put(id,tar);
				}
				else throw new OperacionInvalidaException("el tipo de tarjeta no es correcto");
			}
		}
		else
			throw new OperacionInvalidaException("Tarjeta no se puede crear porque ya existe ese identificador");
		
		return;
	}

/**
* Elimina la estacion deseada de la lista de estaciones
* @param id El identificador de la estacion que deseamos borrar
*/
	public void eliminarEstacion(String id) throws OperacionInvalidaException 
	{
		if	(_estaciones.remove(id)==null)
			throw new OperacionInvalidaException("la estacion no existe");
	    return;
	}

/**
* Elimina la tarjeta deseada de la lista de tarjetas
* @param id El identificador de la tarjeta que deseamos borrar
*/
	public void eliminarTarjeta(String id) throws OperacionInvalidaException 
	{
		if (_tarjetas.remove(id)==null)
			throw new OperacionInvalidaException("Esa tarjeta no existe");
	    return;
	}

/**
* Registra la entrada de una persona en un autobus, llama al metodo correspondiente para efectuar el cobro de la subida, crea esa nueva 
* operacion llamando a su constructor y añade dicha operacion a la tarjeta sobre la que se esta realizando la operacion. 
* @param idTarjeta El identificador de la tarjeta que realiza la subida
* @param idEstacion El identificador de la estacion en la que se sube el usuario
* @param fecha La fecha en la que se encuentra
* @return 0
*/
	public int registrarEntrada(String idTarjeta, String idEstacion, Date fecha) throws OperacionInvalidaException 
	{
		Tarjeta t = (Tarjeta)_tarjetas.get(idTarjeta);
		if (t==null) 
			throw new OperacionInvalidaException(" Id de la tarjeta incorrecta"); 
		else
			if((Estacion)_estaciones.get(idEstacion)==null)
				throw new OperacionInvalidaException("No se puede fichar porque la estación no existe");
			else
			{
				if (t.mirarSaldo()<t.consultarImporte())
					throw new OperacionInvalidaException("No tiene saldo suficiente");
				else
				{
					t.subir();
					int importe=t.consultarImporte();
					Operacion op=new Subir(fecha,importe,t,idEstacion);
					t.añadirOp(op);
				}
			}
		return 0;
	}
	
/**
* Registra la salida de una persona, crea la operacion bajar y la añade a la lista de operaciones de la tarjeta correspondiente.
* @param idTarjeta El identificador de la tarjeta que realiza la salida del autobus
* @param idEstacion La estacion en la cual se produce la salida
* @param fecha La fecha en la cual se produce la bajada
* @return 0
*/
	public int  registrarSalida(String idTarjeta, String idEstacion, Date fecha) throws OperacionInvalidaException 
	{	
		Tarjeta t = (Tarjeta)_tarjetas.get(idTarjeta);
		if (t==null) 
			throw new OperacionInvalidaException("Id de la tarjeta incorrecta"); 
		else
			if ((Estacion)_estaciones.get(idEstacion)==null)
				throw new OperacionInvalidaException("No se puede fichar la salida porque la estación no existe");
			else
			{
				Operacion op=new Bajar(fecha,t,idEstacion);
				t.añadirOp(op);
			}
	    return 0;
	}

/**
* Consulta las operaciones que hizo una tarjeta entre dos fechas, recuperando de la collection que tiene la tarjeta las que se encuentran entre las 
* fechas indicadas y metiendolas en un array para devolver un iterator del mismo.
* @param idTarjeta El identificador de la tarjeta que quiere realizar la consulta.
* @param fechaInicial La fecha desde la cual empezamos a buscar operaciones de la tarjeta.
* @param fechaFinal La fecha asta la cual buscamos operaciones.
* @return iterador El iterador con las operaciones realizadas entre las fechas indicadas.
*/
	public Iterator consultarOperaciones(String idTarjeta, Date fechaInicial, Date fechaFinal) throws OperacionInvalidaException 
	{
		Tarjeta t = (Tarjeta)_tarjetas.get(idTarjeta);
		if (t==null) 
			throw new OperacionInvalidaException(" Id de la tarjeta incorrecta"); 
		else
		{
			Iterator<Operacion> iterador=t.consultarFechas(fechaInicial,fechaFinal);
	   	return iterador;
		}
	}
	
/**
* Transfiere el saldo indicado desde una tarjeta a otra, ambas indicadas, y guarda la operacion en la collection de cada una con la fecha pasada.
* @param idTarjetaOrdenante El identificador de la tarjeta desde la cual se traspasa el saldo
* @param idTarjetaReceptora El identificador de la tarjeta que recibe el ingreso de saldo
* @param importe La cantidad de saldo que vamos a transferir
* @param fecha	La fecha en la cual se realiza la operacion
*/
	public void transferirSaldo(String idTarjetaOrdenante,
		String idTarjetaReceptora, int importe, Date fecha) throws OperacionInvalidaException 
	{
		importe=importe*100;
		Tarjeta tOrdenante = (Tarjeta)_tarjetas.get(idTarjetaOrdenante);
		Tarjeta tReceptora = (Tarjeta)_tarjetas.get(idTarjetaReceptora);
		if(tOrdenante==null || tReceptora==null)
			throw new OperacionInvalidaException("Tarjeta no valida");
		else
			if(consultarSaldo(idTarjetaOrdenante)<importe)
				throw new OperacionInvalidaException("No tiene suficiente saldo");
			else
			{	
				if(consultarSaldo(idTarjetaOrdenante)-importe<0 || consultarSaldo(idTarjetaReceptora)+importe>6000)
					throw new OperacionInvalidaException("No se puede realizar la transferencia, por no cumplir los requisitos");
				else
				{
					tOrdenante.prestar(importe);
					tReceptora.cargar(importe);
					Operacion opOrdenante=new Transferir(fecha,importe,tOrdenante,"TRANSFERENCIA",tReceptora);
					Operacion opReceptora=new Transferir(fecha,importe,tReceptora,"TRANSFERENCIA",tOrdenante);
					tOrdenante.c.add(opOrdenante);
					tReceptora.c.add(opReceptora);
				}
			}
	    return;
	}
        
        

}
